/* * JaamSim Discrete Event Simulation * Copyright (C) 2011 Ausenco Engineering Canada Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaamsim.ui; import java.awt.Component; import java.awt.Cursor; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.event.MouseEvent; import java.util.HashMap; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.ToolTipManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import com.jaamsim.basicsim.ObjectType; import com.jaamsim.controllers.RenderManager; public class EntityPallet extends JFrame implements DragGestureListener { private static EntityPallet myInstance; // only one instance allowed to be open private final JScrollPane treeView; private final JTree tree; private final DefaultMutableTreeNode top; private final DefaultTreeModel treeModel; private EntityPallet() { super( "Model Builder" ); setType(Type.UTILITY); setAutoRequestFocus(false); // Make the x button do the same as the close button setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(FrameBox.getCloseListener("ShowModelBuilder")); tree = new MyTree(); tree.setRootVisible(false); tree.setShowsRootHandles(true); DragSource dragSource = new DragSource(); dragSource.createDefaultDragGestureRecognizer(tree, DnDConstants.ACTION_COPY, this); top = new DefaultMutableTreeNode(); treeModel = new DefaultTreeModel(top); tree.setModel(treeModel); tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION ); // Create the tree scroll pane and add the tree to it treeView = new JScrollPane( tree ); getContentPane().add( treeView ); tree.setRowHeight(25); tree.setCellRenderer(new TreeCellRenderer()); ToolTipManager.sharedInstance().registerComponent(tree); ToolTipManager.sharedInstance().setDismissDelay(600000); setLocation(GUIFrame.COL1_START, GUIFrame.TOP_START); setSize(GUIFrame.COL1_WIDTH, GUIFrame.HALF_TOP); } @Override public void dragGestureRecognized(DragGestureEvent event) { TreePath path = tree.getSelectionPath(); if (path != null) { // Dragged node is a DefaultMutableTreeNode if(path.getLastPathComponent() instanceof DefaultMutableTreeNode) { DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) path.getLastPathComponent(); // This is an ObjectType node if(treeNode.getUserObject() instanceof ObjectType) { ObjectType type = (ObjectType) treeNode.getUserObject(); Cursor cursor = null; if (event.getDragAction() == DnDConstants.ACTION_COPY) { cursor = DragSource.DefaultCopyDrop; } if (RenderManager.isGood()) { // The new renderer is initialized RenderManager.inst().startDragAndDrop(type); event.startDrag(cursor,new TransferableObjectType(type), RenderManager.inst()); } else { event.startDrag(cursor,new TransferableObjectType(type)); } } } } } private void updateTree() { // Create a tree that allows one selection at a time top.removeAllChildren(); HashMap<String, DefaultMutableTreeNode> paletteNodes = new HashMap<>(); for (ObjectType type : ObjectType.getAll()) { if (!type.isDragAndDrop()) continue; String pName = type.getPaletteName(); DefaultMutableTreeNode palNode = paletteNodes.get(pName); if (palNode == null) { palNode = new DefaultMutableTreeNode(pName, true); paletteNodes.put(pName, palNode); top.add(palNode); } DefaultMutableTreeNode classNode = new DefaultMutableTreeNode(type, true); palNode.add(classNode); } treeModel.reload(top); } public synchronized static EntityPallet getInstance() { if (myInstance == null) { myInstance = new EntityPallet(); myInstance.updateTree(); } return myInstance; } /** * Disposes the only instance of the entity pallet */ public synchronized static void clear() { if (myInstance != null) { myInstance.dispose(); myInstance = null; } } private static class TreeCellRenderer extends DefaultTreeCellRenderer { private final ImageIcon icon = new ImageIcon(); @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); // If not a leaf, just return if (!leaf) return this; // If we don't find an ObjectType (likely we will) just return Object userObj = ((DefaultMutableTreeNode)value).getUserObject(); if (!(userObj instanceof ObjectType)) return this; ObjectType type = (ObjectType)userObj; this.setText(type.getName()); if (!RenderManager.isGood()) return this; if (type.getIconImage() == null) return this; icon.setImage(type.getIconImage()); this.setIcon(icon); return this; } } static class MyTree extends JTree { public MyTree() { } /* * override getToolTipText to control what to display */ @Override public String getToolTipText(MouseEvent e) { if(this.getPathForLocation(e.getX(), e.getY()) == null) { return null; } // Obtain the node under the mouse DefaultMutableTreeNode node = (DefaultMutableTreeNode)this.getPathForLocation(e.getX(), e.getY()).getLastPathComponent(); if(node == null) { return null; } Object object = node.getUserObject(); // It is a leaf node if (!(object instanceof ObjectType)) { return null; } ObjectType ot = (ObjectType)object; return GUIFrame.formatToolTip(ot.getName(), ot.getDescription()); } } private final static DataFlavor OBJECT_TYPE_FLAVOR; static { try { // Create OBJECT_TYPE_FLAVOR String objectTypeFlavor = DataFlavor.javaJVMLocalObjectMimeType + ";class=" + TransferableObjectType.class.getName(); OBJECT_TYPE_FLAVOR = new DataFlavor(objectTypeFlavor); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } } private static class TransferableObjectType implements Transferable { private final ObjectType type; TransferableObjectType(ObjectType type) { this.type = type; } @Override public DataFlavor [] getTransferDataFlavors() { return new DataFlavor [] {OBJECT_TYPE_FLAVOR}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return OBJECT_TYPE_FLAVOR.equals(flavor); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (flavor.equals(OBJECT_TYPE_FLAVOR)) { return type; } else { throw new UnsupportedFlavorException(flavor); } } } }